<template>
  <div>
    <div ref="toastUIEditor" class="fullscreen" />
  </div>
</template>

<script>
// 编辑器
import 'codemirror/lib/codemirror.css'
import '@toast-ui/editor/dist/toastui-editor.css'
import Editor from '@toast-ui/editor'

// 颜色选择
import 'tui-color-picker/dist/tui-color-picker.css'
import colorSyntax from '@toast-ui/editor-plugin-color-syntax'

// 代码高亮
import 'highlight.js/styles/github.css'
import hljs from 'highlight.js'
import codeSyntaxHighlight from '@toast-ui/editor-plugin-code-syntax-highlight'

// 图表
import 'tui-chart/dist/tui-chart.css'
import chart from '@toast-ui/editor-plugin-chart'

// 单元格合并
import tableMergedCell from '@toast-ui/editor-plugin-table-merged-cell'

// UML
import uml from '@toast-ui/editor-plugin-uml'

import Fullscreen from './fullscreen.js'
import defaultOptions from './default-options'

const chartOptions = {
  minWidth: 100,
  maxWidth: 600,
  minHeight: 100,
  maxHeight: 300
}

export default {
  name: 'MarkdownEditor',
  props: {
    value: {
      type: String,
      default: ''
    },
    options: {
      type: Object,
      required: false,
      default() {
        return defaultOptions
      }
    },
    // Initial type to show markdown | wysiwyg
    mode: {
      type: String,
      default: 'markdown'
    },
    height: {
      type: String,
      required: false,
      default: '300px'
    },
    language: {
      type: String,
      required: false,
      default: 'en_US'
    },
    // Preview style of Markdown mode tab | vertical
    previewStyle: {
      type: String,
      required: false,
      default: 'vertical'
    },
    enableColorSyntax: {
      type: Boolean,
      required: false,
      default: false
    },
    enableChart: {
      type: Boolean,
      required: false,
      default: false
    },
    enableUml: {
      type: Boolean,
      required: false,
      default: false
    },
    // 上传的地址: 为null时使用默认的图片处理事件
    action: {
      type: String,
      required: false,
      default: null
    },
    // 上传的文件字段名
    name: {
      type: String,
      required: false,
      default: 'file'
    },
    // 上传时附带的额外参数
    data: {
      type: Object,
      required: false,
      default: null
    },
    headers: {
      type: Object,
      default: null
    },
    // 上传成功后的响应函数，请返回图片url
    success: {
      type: Function,
      required: false,
      default: function(res) {
        return res.result
      }
    },
    error: {
      type: Function,
      default: function() {
        console.log('upload fail!')
      }
    }
  },
  data() {
    return {
      editor: null
    }
  },
  computed: {
    editorOptions() {
      const options = Object.assign({}, defaultOptions, this.options)
      options.initialEditType = this.mode
      options.height = this.height
      options.previewStyle = this.previewStyle
      options.language = this.language
      let plugins = [[codeSyntaxHighlight, { hljs }], tableMergedCell]
      if (this.enableColorSyntax) {
        plugins = [...plugins, colorSyntax]
      }
      if (this.enableChart) {
        plugins = [...plugins, [chart, chartOptions]]
      }
      if (this.enableUML) {
        plugins = [...plugins, uml]
      }
      options.plugins = plugins
      return options
    }
  },
  watch: {
    value(newValue, preValue) {
      if (newValue !== preValue && newValue !== this.getValue()) {
        this.setValue(newValue)
      }
    },
    height(newValue) {
      this.editor.height(newValue)
    },
    language(val) {
      this.editor.remove()
      this.initEditor()
    },
    mode(newValue) {
      this.editor.changeMode(newValue)
    }
  },
  mounted() {
    this.initEditor()
    this.initFullScreenItem()
  },
  methods: {
    initEditor() {
      this.options.el = this.$refs.toastUIEditor
      this.editor = new Editor(this.editorOptions)

      if (this.value) {
        this.setValue(this.value)
      }
      this.editor.on('change', () => {
        this.$emit('input', this.getValue())
      })

      if (this.action) {
        // 删除默认addImageBlobHook监听事件
        this.editor.eventManager.removeEventHandler('addImageBlobHook')
        // 添加自定义addImageBlobHook监听事件
        this.editor.eventManager.listen('addImageBlobHook', (blob, callback) => {
          // url为上传后的图片地址
          this.uploadFile(blob, url => {
            callback(url)
          })
        })
      }
    },
    initFullScreenItem() {
      // 添加图标
      const toolbar = this.editor.getUI().getToolbar()
      toolbar.insertItem(23, {
        type: 'button',
        options: {
          event: 'fullscreen',
          tooltip: 'Fullscreen',
          // 使用CSS实现图标
          style: 'margin-top:8px;float: inline-start;box-sizing: border-box;position: relative;width: 14px;height: 14px;border-width: 2px;border-style: dashed dashed dashed dashed;border-color: #000;'
        }
      })

      // 全屏事件与处理
      this.editor.eventManager.addEventType('fullscreen')
      this.editor.eventManager.listen('fullscreen', function() {
        const fs = new Fullscreen()
        // fs.isElementFullScreen() ? fs.exitFullscreen() : fs.Fullscreen('.fullscreen')
        if (fs.isElementFullScreen()) {
          fs.exitFullscreen()
        } else {
          fs.Fullscreen('.fullscreen')
        }
      })
    },
    getValue() {
      return this.editor.getMarkdown()
    },
    setValue(value) {
      this.editor.setMarkdown(value)
    },
    setHtml(value) {
      this.editor.setHtml(value)
    },
    getHtml() {
      return this.editor.getHtml()
    },
    uploadFile(file, callback) {
      const _this = this
      const formData = new FormData()
      // 表单参数赋值
      if (_this.data) {
        Object.keys(_this.data).forEach(function(key) {
          formData.append(key, _this.data[key])
        })
      }
      formData.append(_this.name, file, file.name)

      // 创建XMLHttpRequest对象
      const xhr = new XMLHttpRequest()
      xhr.error = _this.error
      xhr.open('POST', _this.action, true)
      // 设置请求头
      for (const item in _this.headers) {
        if (_this.headers.hasOwnProperty(item) && _this.headers[item] !== null) {
          xhr.setRequestHeader(item, _this.headers[item])
        }
      }
      xhr.send(formData)
      // 返回处理
      xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
          if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
            const response = JSON.parse(xhr.responseText)
            callback(_this.success(response))
          } else {
            console.log('上传失败！')
            _this.error()
          }
        }
      }
    }
  }
}
</script>

<style>
/* 修复全屏后预览背景色为黑色的问题(此处style不能是scoped) */
.te-md-container .te-preview {
  background-color: rgb(255, 255, 255);
}
</style>
